home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / DDJ0992.ARJ / LISTING2.ASC < prev    next >
Text File  |  1992-08-10  |  16KB  |  717 lines

  1.  
  2.  
  3. /*
  4. ** Desciption of AMD Am9513 registers and modes
  5. */
  6.  
  7. /* commands */
  8. #define CMD_SET_DPR(element, group)    (element | group)
  9. #define CMD_ARM                    0x20
  10. #define CMD_LOAD                    0x40
  11. #define CMD_LOAD_AND_ARM            0x60
  12. #define    CMD_SAVE                0xA0
  13. #define    CMD_DISARM                0xC0
  14. #define CMD_MASTER_RESET            0xFF
  15.  
  16. /* for specifying counters with commands */
  17. #define CMD_COUNTER(n)            (1 << (n-1))
  18.  
  19. /* element pointers for the Data Pointer Register */
  20. #define ELEMENT_CMR            000
  21. #define ELEMENT_CLR            010
  22. #define ELEMENT_CHR            020
  23. #define ELEMENT_CHR_ONLY        030
  24. #define ELEMENT_AR1            000
  25. #define ELEMENT_AR2            010
  26. #define ELEMENT_MMR            020
  27. #define ELEMENT_SR_ONLY            030
  28.  
  29. /* group pointers for the Data Pointer Register */
  30. #define GROUP_CNTR(n)    (n)
  31. #define GROUP_CNTRL        007
  32.  
  33. /* master mode register settings */
  34. #define    MMR_SCALER_BINARY    0x0000
  35. #define    MMR_SCALER_BCD        0x8000
  36. #define MMR_DP_INC            0x0000
  37. #define MMR_DP_NOINC            0x4000
  38.  
  39. /* counter mode register settings */
  40. #define CMR_GATE_NONE            0x0000
  41. #define    CMR_GATE_EDGE_HIGH    0xC000
  42. #define CMR_EDGE_RISING            0x0000
  43. #define CMR_EDGE_FALLING        0x1000
  44. #define CMR_SOURCE_F1            0x0B00
  45. #define CMR_SOURCE_F2            0x0C00
  46. #define CMR_SOURCE_F3            0x0D00
  47. #define CMR_SOURCE_F4            0x0E00
  48. #define CMR_SOURCE_F5            0x0F00
  49. #define CMR_COUNT_ONCE            0x0000
  50. #define CMR_COUNT_REPEAT        0x0020
  51. #define    CMR_MODE_BINARY        0x0000
  52. #define    CMR_MODE_BCD        0x0010
  53. #define CMR_DIR_DOWN            0x0000
  54. #define CMR_DIR_UP            0x0008
  55. #define CMR_OUT_INACTIVE_LOW        0x0000
  56. #define CMR_OUT_PULSE_HIGH        0x0001
  57. #define CMR_OUT_TOGGLE            0x0002
  58. #define CMR_OUT_INACTIVE_HIGH        0x0004
  59. #define    CMR_OUT_PULSE_LOW        0x0005
  60.  
  61. #define am9513_reset(cmd_port) am9513_command(cmd_port, CMD_MASTER_RESET)
  62.  
  63. extern void am9513_command();
  64. extern void am9513_output();
  65. extern unsigned short am9513_input();
  66. extern int am9513_set_period();
  67.  
  68. #define TIME_DRT    0
  69. #define    TIME_IST    1
  70. #define TIME_INT    2
  71. #define    TIME_SYS    3
  72. #define    TIME_TRT    4
  73. #define    NUM_TIMES    5
  74.  
  75. extern unsigned short    times[];
  76. extern unsigned int    overruns;
  77. extern unsigned long    period;
  78.  
  79. /*
  80. ** Routines for interfacing with the timer.
  81. */
  82.  
  83. #include <stdio.h>
  84. #include <errno.h>
  85. #include "timer.h"
  86. #include "timer_ioctl.h"
  87.  
  88. static int fd;
  89.  
  90. unsigned long period;
  91. unsigned short times[NUM_TIMES];
  92. unsigned int overruns;
  93.  
  94. void init_timer(name, desired_period)
  95. char *name;
  96. unsigned long desired_period;
  97. {
  98.     if ((fd = open(name, 0)) == -1) {
  99.         (void) fprintf(stderr, "open(%s): %s\n", name, CURERRMSG);
  100.         exit(1);
  101.     }
  102.     period = desired_period;
  103.     if (period) {
  104.         if (ioctl(fd, TIMER_PERIOD_SET, &period) == -1) {
  105.             perror("ioctl(TIMER_PERIOD_SET)");
  106.             exit(1);
  107.         }
  108.     } else {
  109.         if (ioctl(fd, TIMER_PERIOD_GET, &period) == -1) {
  110.             perror("ioctl(TIMER_PERIOD_GET)");
  111.             exit(1);
  112.         }
  113.     }
  114. }
  115.  
  116. void wait_for_interrupt()
  117. {
  118.     struct timer_measurements m;
  119.     int i;
  120.  
  121.     if (ioctl(fd, TIMER_WAIT_FOR_INT, &m) == -1) {
  122.         perror("ioctl(TIMER_WAIT_FOR_INT)");
  123.         exit(1);
  124.     }
  125.     if (ioctl(fd, TIMER_READ, ×[TIME_TRT]) == -1) {
  126.         perror("ioctl(TIMER_READ)");
  127.         exit(1);
  128.     }
  129.     times[TIME_DRT] = m.drt;
  130.     times[TIME_IST] = m.ist;
  131.     times[TIME_INT] = m.drt + m.ist;
  132.     times[TIME_SYS] = times[TIME_TRT] - times[TIME_INT];
  133.     overruns = m.overruns;
  134. }
  135.  
  136. #include <stdio.h>
  137. #include <stdlib.h>
  138. #include <pthread.h>
  139.  
  140. static pthread_mutex_t mutex;
  141. static pthread_cond_t write_cond; /* O.K. to write */
  142. static pthread_cond_t read_cond; /* O.K. to read */
  143. static int readers_done;
  144. int *done;
  145. static int num_readers;
  146.  
  147. void init_synch(readers)
  148. int readers;
  149. {
  150.     int i;
  151.  
  152.     if (pthread_mutex_init(&mutex, pthread_mutexattr_default) == -1) {
  153.         perror("pthread_mutex_init");
  154.         exit(1);
  155.     }
  156.     if (pthread_cond_init(&write_cond, pthread_condattr_default) == -1) {
  157.         perror("pthread_cond_init");
  158.         exit(1);
  159.     }
  160.     if (pthread_cond_init(&read_cond, pthread_condattr_default) == -1) {
  161.         perror("pthread_cond_init");
  162.         exit(1);
  163.     }
  164.     num_readers = readers;
  165.     readers_done = num_readers;
  166.     if (!(done = (int *)malloc(num_readers * sizeof(int)))) {
  167.         perror("malloc");
  168.         exit(1);
  169.     }
  170.     for (i = 0; i < num_readers; i++) done[i] = 1;
  171. }
  172.  
  173. void wait_for_consumers()
  174. {
  175.     pthread_mutex_lock(&mutex);
  176.     if (readers_done != num_readers) {
  177.         pthread_cond_wait(&write_cond, &mutex);
  178.     }
  179.     pthread_mutex_unlock(&mutex);
  180. }
  181.  
  182. void signal_consumers()
  183. {
  184.     int i;
  185.  
  186.     pthread_mutex_lock(&mutex);
  187.     readers_done = 0;
  188.     for (i = 0; i < num_readers; i++) done[i] = 0;
  189.     pthread_cond_broadcast(&read_cond);
  190.     pthread_mutex_unlock(&mutex);
  191. }
  192.  
  193. void signal_producer(id)
  194. int id;
  195. {
  196.     pthread_mutex_lock(&mutex);
  197.     readers_done++;
  198.     if (readers_done == num_readers) {
  199.         pthread_cond_signal(&write_cond);
  200.     }
  201.     done[id]  = 1;
  202.     pthread_mutex_unlock(&mutex);
  203. }
  204.  
  205. void wait_for_producer(id)
  206. int id;
  207. {
  208.     pthread_mutex_lock(&mutex);
  209.     if (done[id]) pthread_cond_wait(&read_cond, &mutex);
  210.     pthread_mutex_unlock(&mutex);
  211. }
  212.  
  213. /*
  214. ** Program to simulate a real-time system and measure and/or record
  215. **     1. Device driver interrupt response time
  216. **     2. Device driver interrupt service time
  217. **     3. Task response time
  218. **
  219. ** Each measured time is exagerated by a constant amount of time equal to the
  220. ** length of time it takes to make the measurement.
  221. */
  222.  
  223. #include <stdlib.h>
  224. #include <stdio.h>
  225. #include <pthread.h>
  226. #include <types.h>
  227. #include <sched.h>
  228.  
  229. #define PRODUCER_PRIO 31
  230.  
  231. extern void producer();
  232. extern void display(), consumer();
  233.  
  234. struct {
  235.     void (*f)();    /* task entry point                                */
  236.     int p_bias;        /* priority relative to producer (always negative) */
  237. } consumers[] = {
  238.     { display, -1 },
  239.     { consumer, -1 }
  240. };
  241.  
  242. #define NCONSUMERS (sizeof consumers / sizeof consumers[0])
  243.  
  244. static void start_consumers()
  245. {
  246.     int i;
  247.     pthread_attr_t attr;
  248.     pthread_t tid;
  249.  
  250.     for (i = 0; i < NCONSUMERS; i++) {
  251.         pthread_attr_create(&attr);
  252.         pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
  253.         pthread_attr_setprio(&attr, PRODUCER_PRIO + consumers[i].p_bias);
  254.         if (pthread_create(&tid, attr, consumers[i].f, i) == -1) {
  255.             perror("pthread_create");
  256.             exit(1);
  257.         }
  258.     }
  259. }
  260.  
  261. main(argc, argv)
  262. int argc;
  263. char *argv[];
  264. {
  265.     unsigned long period;
  266.     char *ptr;
  267.  
  268.     if (argc < 2 || argc > 3) {
  269.         fprintf(stderr, "Usage: %s timer_device [ period ]\n", argv[0]);
  270.         exit(1);
  271.     }
  272.     if (argc == 3) {
  273.         period = strtol(argv[2], &ptr, 0);
  274.         if (*ptr) {
  275.             (void) fprintf(stderr, "%s: invalid period %s\n",argv[0],argv[2]);
  276.             exit(1);
  277.         }
  278.     } else {
  279.         period = 0l;
  280.     }
  281.  
  282.     if (setprio(0, PRODUCER_PRIO) == -1) {
  283.         perror("setprio");
  284.         exit(1);
  285.     }
  286.     init_synch(NCONSUMERS);
  287.     start_consumers();
  288.     init_timer(argv[1], period);
  289.     producer();
  290.  
  291.     exit(0);
  292. }
  293.  
  294. void producer()
  295. {
  296.     for (;;) {
  297.         wait_for_interrupt();
  298.         signal_consumers();
  299.         wait_for_consumers();
  300.     }
  301. }
  302.  
  303. /*
  304. ** Consumer which writes data to screen.
  305. */
  306.  
  307. #include <stdio.h>
  308. #include <pthread.h>
  309. #include <types.h>
  310. #include <sched.h>
  311. #include "timer.h"
  312.  
  313. static unsigned short min_bufs[2][NUM_TIMES];
  314. static unsigned short max_bufs[2][NUM_TIMES];
  315. static unsigned short *min;
  316. static unsigned short *max;
  317. static int overrun_counts[2];
  318. static pthread_mutex_t mutexes[2];
  319. static int fill_buf = 0, show_buf = 0;
  320.  
  321. static void reset_arrays(mins, maxs)
  322. unsigned short *mins, *maxs;
  323. {
  324.     int i;
  325.  
  326.     for (i = 0; i < NUM_TIMES; i++) {
  327.         mins[i] = 0xffff;
  328.         maxs[i] = 0x0;
  329.     }
  330. }
  331.  
  332. static void show()
  333. {
  334.     int i;
  335.     unsigned short *min, *max;
  336.  
  337.     for (;;) {
  338.         min = min_bufs[show_buf];
  339.         max = max_bufs[show_buf];
  340.         pthread_mutex_lock(&mutexes[show_buf]);
  341.         for (i = 0; i < NUM_TIMES; i++) {
  342.             unlocked_printf("%3u %3u | ", min[i], max[i]);
  343.             fflush(stdout);
  344.         }
  345.         unlocked_printf("%u\n", overrun_counts[show_buf]);
  346.         reset_arrays(min, max);
  347.         overrun_counts[show_buf] = 0;
  348.         pthread_mutex_unlock(&mutexes[show_buf]);
  349.         show_buf ^= 1;
  350.     }
  351. }
  352.  
  353. static void create_show()
  354. {
  355.     pthread_attr_t attr;
  356.     tid_t tid;
  357.  
  358.     pthread_mutex_init(&mutexes[0], pthread_mutexattr_default);
  359.     pthread_mutex_init(&mutexes[1], pthread_mutexattr_default);
  360.     pthread_mutex_lock(&mutexes[0]);
  361.  
  362.     pthread_attr_create(&attr);
  363.     pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
  364.     pthread_attr_setprio(&attr, getprio(0) - 1);
  365.     if (pthread_create(&tid, attr, show, 0) == -1) {
  366.         perror("pthread_create");
  367.         exit(1);
  368.     }
  369. }
  370.  
  371. void display(id)
  372. int id;
  373. {
  374.     int i, j;
  375.     unsigned long iterations;
  376.     unsigned long remaining;
  377.  
  378.     reset_arrays(min_bufs[0], max_bufs[0]);
  379.     reset_arrays(min_bufs[1], max_bufs[1]);
  380.     min = min_bufs[fill_buf];
  381.     max = max_bufs[fill_buf];
  382.  
  383.     printf("Dividing by %lu\n", period);
  384.     iterations = 5000000 / period;
  385.     if (!iterations) iterations = 1;
  386.     remaining = iterations;
  387.  
  388.     create_show();
  389.  
  390.     for (;;) {
  391.         wait_for_producer(id);
  392.         for (i = 0; i < NUM_TIMES; i++) {
  393.             min[i] = times[i] < min[i] ? times[i] : min[i];
  394.             max[i] = times[i] > max[i] ? times[i] : max[i];
  395.         }
  396.         overrun_counts[fill_buf] += overruns;
  397.         if (!--remaining) {
  398.             pthread_mutex_unlock(&mutexes[fill_buf]);
  399.             fill_buf ^= 1;
  400.             min = min_bufs[fill_buf];
  401.             max = max_bufs[fill_buf];
  402.             remaining = iterations;
  403.             pthread_mutex_lock(&mutexes[fill_buf]);
  404.         }
  405.         signal_producer(id);
  406.     }
  407. }
  408.  
  409. void consumer(id)
  410. int id;
  411. {
  412.     for (;;) {
  413.         wait_for_producer(id);
  414.         signal_producer(id);
  415.     }
  416. }
  417.  
  418. /*
  419. ** Device driver for the Industrial Computer Source model DCC20A
  420. ** timer/counter board based on four AMD Am9513 System Timing Controllers
  421. **
  422. ** Configuration assumptions:
  423. */
  424.  
  425. #include <kernel.h>
  426. #include <mem.h>
  427. #include <file.h>
  428. #include <errno.h>
  429. #include "timer_ioctl.h"
  430. #include "timer_info.h"
  431. #include "am9513.h"
  432.  
  433. struct timer_statics {
  434.     unsigned long        period;
  435.     unsigned long        default_period;
  436.     int                irq;
  437.     int                closed;
  438.     int                interrupt_sem;
  439.     unsigned int        overruns;
  440.     unsigned short        port;
  441.     unsigned short        drt;
  442.     unsigned short        ist_delta;
  443.     unsigned short        short_period;
  444. };
  445.  
  446. void timer_interrupt(s)
  447. struct timer_statics *s;
  448. {
  449.     am9513_command(s->port+1, CMD_SAVE | CMD_COUNTER(1));
  450.     if (s->interrupt_sem < 0) {
  451.         ssignal(&s->interrupt_sem);
  452.         s->drt = am9513_input(s->port);
  453.         am9513_command(s->port+1, CMD_SAVE | CMD_COUNTER(1));
  454.         s->ist_delta = am9513_input(s->port);
  455.     } else {
  456.         s->overruns++;
  457.     }
  458. }
  459.  
  460. struct timer_statics *timer_install(info)
  461. struct timer_info *info;
  462. {
  463.     struct timer_statics *s;
  464.     int port;
  465.  
  466.     /* reset the Am9513 (this will insure the interrupt is off) */
  467.     am9513_reset(info->port+1);    
  468.  
  469.     /* allocate the data structure to hold the static variables */
  470.     s = (struct timer_statics *)sysbrk((long)sizeof *s);
  471.     if (!s) return (struct timer_statics *)SYSERR;
  472.  
  473.     /* initialize the static variables */
  474.     s->irq = info->irq;
  475.     s->port = info->port;
  476.     s->default_period = info->period;
  477.     s->closed = 1;
  478.  
  479.     return s;
  480. }
  481.  
  482. void timer_uninstall(s)
  483. struct timer_statics *s;
  484. {
  485.     sysfree(s, (long)sizeof *s);
  486. }
  487.  
  488. int timer_open(s, devno, f)
  489. struct timer_statics *s;
  490. int devno;
  491. struct file *f;
  492. {
  493.     /* make sure the monor device number is 0 */
  494.     if (minor(devno)) {
  495.         pseterr(ENXIO);
  496.         return SYSERR;
  497.     }
  498.  
  499.     /* if the device was closed reset the defaults and interrupt handling */
  500.     if (s->closed) {
  501.         s->closed = 0;
  502.         s->period = s->default_period;
  503.         s->interrupt_sem = 0;
  504.         iointset(s->irq, timer_interrupt, s);
  505.         (void) am9513_set_period(s->port+1, s->port, &s->period);
  506.         s->short_period = s->period > 0xFFFF ? 0xFFFF : s->period;
  507.         s->overruns = 0;
  508.         am9513_command(s->port+1,CMD_SET_DPR(ELEMENT_CMR,GROUP_CNTR(1)));
  509.         am9513_output(s->port,
  510.                             CMR_GATE_EDGE_HIGH|CMR_SOURCE_F1|CMR_COUNT_REPEAT);
  511.         am9513_command(s->port+1,CMD_SET_DPR(ELEMENT_CLR,GROUP_CNTR(1)));
  512.         am9513_output(s->port, s->short_period);
  513.         am9513_command(s->port+1,CMD_SET_DPR(ELEMENT_CHR,GROUP_CNTR(1)));
  514.         am9513_command(s->port+1, CMD_LOAD_AND_ARM | CMD_COUNTER(1));
  515.     }
  516.  
  517.     return OK;
  518. }
  519.  
  520. int timer_close(s, f)
  521. struct timer_statics *s;
  522. struct file *f;
  523. {
  524.     /* reset the Am9513 (this will insure the interrupt is off) */
  525.     am9513_reset(s->port+1);    
  526.  
  527.     s->closed = 1;
  528.     iointclr(s->irq);
  529.  
  530.     return OK;
  531. }
  532.  
  533. int timer_rws()
  534. {
  535.     pseterr(EINVAL);
  536.     return SYSERR;
  537. }
  538.  
  539. int timer_ioctl(s, f, command, arg)
  540. struct timer_statics *s;
  541. struct file *f;
  542. int command;
  543. void *arg;
  544. {
  545.     int ps;
  546.     struct timer_measurements *m = (struct timer_measurements *)arg;
  547.  
  548.     switch (command) {
  549.         case TIMER_WAIT_FOR_INT:
  550.             if (arg) {
  551.                 if (wbounds(arg) < sizeof(struct timer_measurements)) {
  552.                 pseterr(EFAULT);
  553.                 return SYSERR;
  554.                 }
  555.                 disable(ps);
  556.                 swait(&s->interrupt_sem, -1);
  557.                 m->ist = s->drt - s->ist_delta;
  558.                 m->drt = s->short_period - s->drt;
  559.                 m->overruns = s->overruns;
  560.                 s->overruns = 0;
  561.                 restore(ps);
  562.             } else {
  563.                 disable(ps);
  564.                 swait(&s->interrupt_sem, -1);
  565.                 s->overruns = 0;
  566.                 restore(ps);
  567.             }
  568.             break;
  569.         
  570.         case TIMER_PERIOD_SET:
  571.             if (wbounds(arg) < sizeof(long)) {
  572.                 pseterr(EFAULT);
  573.                 return SYSERR;
  574.             }
  575.             s->period = *(unsigned long *)arg;
  576.             if (am9513_set_period(s->port+1, s->port, &s->period) == -1) {
  577.                 pseterr(EINVAL);
  578.                 return SYSERR;
  579.             }
  580.             s->short_period = s->period > 0xFFFF ? 0xFFFF : s->period;
  581.             *(unsigned long *)arg = s->period;
  582.  
  583.             am9513_command(s->port+1,CMD_SET_DPR(ELEMENT_CLR,GROUP_CNTR(1)));
  584.             am9513_output(s->port, s->short_period);
  585.             am9513_command(s->port+1,CMD_SET_DPR(ELEMENT_CHR,GROUP_CNTR(1)));
  586.             am9513_command(s->port+1, CMD_LOAD_AND_ARM | CMD_COUNTER(1));
  587.  
  588.             break;
  589.  
  590.         case TIMER_PERIOD_GET:
  591.             if (wbounds(arg) < sizeof(long)) {
  592.                 pseterr(EFAULT);
  593.                 return SYSERR;
  594.             }
  595.             *(unsigned long *)arg = s->period;
  596.             break;
  597.         
  598.         case TIMER_READ:
  599.             disable(ps);
  600.             am9513_command(s->port+1, CMD_SAVE | CMD_COUNTER(1));
  601.             if (wbounds(arg) < sizeof(short)) {
  602.                 restore(ps);
  603.                 pseterr(EFAULT);
  604.                 return SYSERR;
  605.             }
  606.             *(unsigned short *)arg = s->short_period - am9513_input(s->port);
  607.             restore(ps);
  608.             break;
  609.         
  610.         default:
  611.             pseterr(EINVAL);
  612.             return SYSERR;
  613.     }
  614.     return OK;
  615. }
  616.  
  617. #include <dldd.h>
  618. static struct dldd entry_points = {
  619.   timer_open,        /* open      */
  620.   timer_close,        /* close     */
  621.   timer_rws,        /* read      */
  622.   timer_rws,        /* write     */
  623.   timer_rws,        /* select    */
  624.   timer_ioctl,        /* ioctl     */
  625.   timer_install,    /* install   */
  626.   timer_uninstall    /* uninstall */
  627. };
  628.  
  629. #include "am9513.h"
  630.  
  631. #define MAX_TIMER_VALUE ((1<<16)-1)
  632.  
  633. struct {
  634.     unsigned long divisor;
  635.     unsigned short scaler_mode;
  636.     unsigned short count_src;
  637. } divisors[] = {
  638.     { 1,        MMR_SCALER_BINARY,    CMR_SOURCE_F1 },
  639.     { 10,        MMR_SCALER_BCD,        CMR_SOURCE_F2 },
  640.     { 16,        MMR_SCALER_BINARY,    CMR_SOURCE_F2 },
  641.     { 100,    MMR_SCALER_BCD,        CMR_SOURCE_F3 },
  642.     { 256,    MMR_SCALER_BINARY,    CMR_SOURCE_F3 },
  643.     { 1000,    MMR_SCALER_BCD,        CMR_SOURCE_F4 },
  644.     { 4096,    MMR_SCALER_BINARY,    CMR_SOURCE_F4 },
  645.     { 10000,    MMR_SCALER_BCD,        CMR_SOURCE_F5 },
  646.     { 65536,    MMR_SCALER_BINARY,    CMR_SOURCE_F5 }
  647. };
  648. #define NDIVISORS (sizeof divisors / sizeof divisors[0])
  649.  
  650. void am9513_command(cmd_port, command)
  651. unsigned short cmd_port;
  652. unsigned char command;
  653. {
  654.     asm {
  655.         mov DX, cmd_port[EBP]
  656.         mov AL, command[EBP]
  657.         out DX, AL
  658.     }
  659. }
  660.  
  661. void am9513_output(data_port, data)
  662. unsigned short data_port, data;
  663. {
  664.     asm {
  665.         mov DX, data_port[EBP]
  666.         mov AX, data[EBP]
  667.         out DX, AL
  668.         shr AX, 8
  669.         out DX, AL
  670.     }
  671. }
  672.  
  673. unsigned short am9513_input(data_port)
  674. unsigned short data_port;
  675. {
  676.     asm {
  677.         xor EAX, EAX
  678.         mov DX, data_port[EBP]
  679.         in AL, DX
  680.         mov BL, AL
  681.         in AL, DX
  682.         shl AX, 8
  683.         mov AL, BL
  684.     }
  685. }
  686.  
  687. int am9513_set_period(cmd_port, data_port, p_period)
  688. unsigned short cmd_port, data_port;
  689. unsigned long *p_period;
  690. {
  691.     unsigned long count;
  692.     int i;
  693.  
  694.     count = *p_period;
  695.  
  696.     for (i = 0; i < NDIVISORS; i++) {
  697.         if (count / divisors[i].divisor <= MAX_TIMER_VALUE) break;
  698.     }
  699.     if (i == NDIVISORS) return -1;
  700.  
  701.     count /= divisors[i].divisor;
  702.  
  703.     *p_period = count * divisors[i].divisor;
  704.  
  705.     am9513_command(cmd_port, CMD_SET_DPR(ELEMENT_MMR, GROUP_CNTRL));
  706.     am9513_output(data_port, divisors[i].scaler_mode | MMR_DP_NOINC);
  707.     am9513_command(cmd_port, CMD_SET_DPR(ELEMENT_CMR, GROUP_CNTR(5)));
  708.     am9513_output(data_port,
  709.                 divisors[i].count_src | CMR_COUNT_REPEAT | CMR_OUT_PULSE_HIGH);
  710.     am9513_command(cmd_port, CMD_SET_DPR(ELEMENT_CLR, GROUP_CNTR(5)));
  711.     am9513_output(data_port, count);
  712.     am9513_command(cmd_port, CMD_LOAD_AND_ARM | CMD_COUNTER(5));
  713.  
  714.     return 0;
  715. }
  716.  
  717.